<!DOCTYPE html>
<html>
<head>
  <title>router</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <style type="text/css">
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    html, body {
      height: 100%;
    }
    #app {
      height: 100%;
    }
  </style>
</head>
<body>
  <div id="app">
    <keep-alive :include="includes">
      <router-view></router-view>
    </keep-alive>
  </div>
  <script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script>
  <script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.js"></script>
  <script>
    const Index = {
      name: 'Index',
      template:
      `<div>
        首页
        <div>
          <router-link :to="{ name: 'List' }">Go to List</router-link>
        </div>
      </div>`,
      mounted() {
        console.warn('Main', 'mounted');
      },
    };

    const List = {
      name: 'List',
      template: 
      `<div style="display: flex;flex-direction: column;height: 100%;">
        <div>列表页</div>
        <div style="flex: 1;overflow: scroll;" v-keep-position="'list1'">
          <div v-for="item in list" :key="item.id">
            <router-link style="line-height: 100px;display:block;" :to="{ name: 'Detail', params: { id: item.id } }">
              {{item.name}}
            </router-link>
          </div>
        </div>
        <div style="flex: 1;overflow: scroll;" v-keep-position="'list2'">
          <div v-for="item in list" :key="item.id">
            <router-link style="line-height: 100px;display:block;" :to="{ name: 'Detail', params: { id: item.id } }">
              {{item.name}}
            </router-link>
          </div>
        </div>
      </div>`,
      data() {
        return {
          list: new Array(10).fill(1).map((_,index) => {
            return {id: index + 1, name: `item${index + 1}`};
          }),
        };
      },
      mounted() {
        console.warn('List', 'mounted');
      },
      activated() {
        console.warn('List', 'activated');
      },
      deactivated() {
        console.warn('List', 'deactivated');
      },
    };

    const Detail = {
      name: 'Detail',
      template:
      `<div>
        详情页
        <div>
          {{$route.params.id}}
        </div>
      </div>`,
      mounted() {
        console.warn('Detail', 'mounted');
      },
    };

    const routes = [
      { path: '', name: 'Main', component: Index },
      { path: '/list', name: 'List', component: List },
      { path: '/detail/:id', name: 'Detail', component: Detail },
    ];

    const router = new VueRouter({
      routes,
    });

    /**
     * 移动端路由
     */
    let dir = 1;
    const includes = [];
    const positions = [];

    const routerPush = router.push;
    router.push = function push(...args) {
      dir = 1;
      routerPush.apply(router, args);
    };

    router.afterEach((to, from) => {
      if (dir === 1) {
        includes.push(to.name);
        positions.push({});
      } else if (dir === -1) {
        includes.pop();
        unkeepPosition(positions.pop({}));
        restorePosition();
      }
      dir = -1;
    });

    Vue.directive('keep-position', {
      bind(el, { value }) {
        const parent = positions[positions.length - 1];
        const obj = {
          x: 0,
          y: 0,
        };
        const key = value;
        parent[key] = obj;
        obj.el = el;
        obj.handler = function ({ currentTarget }) {
          obj.x = currentTarget.scrollLeft;
          obj.y = currentTarget.scrollTop;
        };
        el.addEventListener('scroll', obj.handler);
      },
    });

    const restorePosition = function () {
      Vue.nextTick(() => {
        const parent = positions[positions.length - 1];
        for (let key in parent) {
          const { el, x, y } = parent[key];
          el.scrollLeft = x;
          el.scrollTop = y;
        }
      });
    };

    const unkeepPosition = function (parent) {
      for (let key in parent) {
        const obj = parent[key];
        obj.el.removeEventListener('scroll', obj.handler);
      }
    };

    /** TODO
     * 循环的页面关系
     */

    const app = new Vue({
      router,
      data() {
        return {
          includes,
        };
      },
    }).$mount('#app');
  </script>
</body>
</html>
